home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2001 December / pcwk12201b.iso / Wersje pelne i specjalne / Winamp 2.77 i 3.0beta / wasabi-sdk_beta1.exe / studio / ExampleB / exampleBwnd.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  20KB  |  544 lines

  1. /*
  2.  
  3.   Nullsoft WASABI Source File License
  4.  
  5.   Copyright 1999-2001 Nullsoft, Inc.
  6.  
  7.     This software is provided 'as-is', without any express or implied
  8.     warranty.  In no event will the authors be held liable for any damages
  9.     arising from the use of this software.
  10.  
  11.     Permission is granted to anyone to use this software for any purpose,
  12.     including commercial applications, and to alter it and redistribute it
  13.     freely, subject to the following restrictions:
  14.  
  15.     1. The origin of this software must not be misrepresented; you must not
  16.        claim that you wrote the original software. If you use this software
  17.        in a product, an acknowledgment in the product documentation would be
  18.        appreciated but is not required.
  19.     2. Altered source versions must be plainly marked as such, and must not be
  20.        misrepresented as being the original software.
  21.     3. This notice may not be removed or altered from any source distribution.
  22.  
  23.  
  24.   Brennan Underwood
  25.   brennan@nullsoft.com
  26.  
  27. */
  28.  
  29. // ===========================================================================
  30. //
  31. //    NULLSOFT WASABI SDK EXAMPLE PROJECTS
  32. //
  33. //      File:     ExampleBWnd.cpp
  34. //
  35. //!##   Purpose:  This is the source module that contains the top-level 
  36. //!##             methods we'll be using for the construction of the ExampleB
  37. //!##             window object.
  38. //
  39. //      Requires: Please read ExampleBWnd.h first.
  40. //
  41. //      Notes:    A note on the comments in this document:
  42. //                Notes that begin with *** are important notes that everyone
  43. //                needs to read.  The other comments assist readability or
  44. //                explain the thinking behind sections of code which may not
  45. //                be immediately obvious to the novice programmer.
  46. //
  47. //                Or I'm just typing to hear myself clickyclack.
  48. //
  49.  
  50. // Always begin with including std.h
  51. #include "../common/std.h"
  52.  
  53. #include "ExampleB.h"
  54. #include "ExampleBwnd.h"
  55.  
  56. // To be able to have Example1 as a Child Window
  57. #include "../example1/Example1Wnd.h"  
  58. // Child Window Notification Messages
  59. #include "../common/notifmsg.h" 
  60. // Core Handle for control of mp3 playback.
  61. #include "../common/corehandle.h"
  62. // Header to allow us to throw a textbar in there.
  63. #include "../common/textbar.h"
  64. // Header for generic guid mangling.
  65. #include "../common/nsguid.h"
  66. // Header for the _ object for language translation.
  67. #include "../common/xlatstr.h"
  68. // Header for ContWnd
  69. #include "../common/contwnd.h"
  70.  
  71.  
  72. // Oh, buttons get included up in there somewhere, too....
  73.  
  74.  
  75. // ===========================================================================
  76. //
  77. //  EXAMPLEB: Static Globals
  78. //
  79.  
  80. // A simple little static to help us lay out buttons, etc.
  81. static inline int PostIncReturn(int &counter, int amount)
  82. {
  83.   // Return the given counter value and increment it by ``amount''
  84.   int retval = counter;
  85.   counter += amount;
  86.   return retval;
  87. }
  88.  
  89. // ===========================================================================
  90. //
  91. //  EXAMPLEB: "ExampleBWnd::ExampleBWnd"
  92. //
  93. //    *** We commit the tasks of 1) Instantiation and
  94. //        2) Assembly in the CONSTRUCTOR of the containment
  95. //        class.  The third primary task to occur before
  96. //        normal framelooped behaviour, Initialization,
  97. //        occurs AUTOMATICALLY for ALL contained objects by
  98. //        the default baseclass onInit() event handler.
  99. //
  100. //    *** In addition, it is important to note that any GUI
  101. //        objects that take pointers to other gui objects have
  102. //        the responsibility for deleting their interred pointrs
  103. //        upon the destruction of that object.
  104. //
  105. ExampleBWnd::ExampleBWnd( void ) :
  106.   myXMLURLBuffer()  // Let our string member fully construct.
  107. {
  108.   // Blah blah blah... default initialization values... yadda yadda yadda
  109.   myUrlGrab = NULL;
  110.   myDownloadState = EXB_DOWNLOAD_READY;
  111.  
  112.   //
  113.   // In order to logically segregate the functions, we're
  114.   // going to make a new method for our control class that
  115.   // we call "createChildWindows" -- here's where we'll setup the
  116.   // user interface objects that will exist in our sandbox.
  117.   //
  118.   //  (This lets me move that whole block of code around if I
  119.   //   screw up and put it in the wrong place, or the API changes)
  120.   int myRetval = createChildWindows();
  121.   // and yes, we ignore the return code from the fxn.
  122.   // what are you going to do about it, in a constructor?
  123. }
  124.  
  125. // ===========================================================================
  126. //
  127. //  EXAMPLEB: "ExampleBWnd::onInit()"
  128. //
  129. //  So, okay, the setting of a timer falls neatly under the heading of 
  130. //    "initialization activities."  This is how we latch our initialization
  131. //    event and perform our method overrides.  STANDARD C++ procedure, of
  132. //    course, but I'm gonna be explicit about it, just so there's no problems:
  133. int ExampleBWnd::onInit() {
  134.   // By calling our parent class' onInit method, we aught to have all
  135.   // of our children properly initialized as well.
  136.   int retval = EXAMPLEBWND_PARENT::onInit();
  137.  
  138.   setTimer(EXB_TIMER_ID, EXB_TIMER_DUR);
  139.     return retval;
  140. }
  141.  
  142. // ===========================================================================
  143. //
  144. //  EXAMPLEB: "ExampleBWnd::timerCallback(int id)"
  145. //
  146. void ExampleBWnd::timerCallback(int id)
  147. {
  148.     // Anyhow, so, we test the ID here to make sure we know
  149.     // which timer fell out.  Since we only have one timer,
  150.     // we didn't HAVE to switch on it, but it helps to setup
  151.     // your frameworks like this anyhow.  Multiple if-chains
  152.     // make things hard to read.
  153.     switch (id)
  154.     {
  155.         case EXB_TIMER_ID:  
  156.             // Periodically, handle URL downloading.
  157.             pollDownloadState();
  158.             break;
  159.  
  160.         default:
  161.             // If, by some vague stretch of our crazed imaginations,
  162.             // someone ELSE in our window derivation chain decided to
  163.             // send up a timer, we must then pass it along up the chain.
  164.             EXAMPLEBWND_PARENT::timerCallback(id);
  165.             // NO, DO NOT QUESTION, JUST DO IT.  DO IT!     DO IT NOW!!!
  166.             //
  167.             //            grr!
  168.             //
  169.             break;
  170.     };
  171.     
  172. }
  173.  
  174. // ===========================================================================
  175. //
  176. //  EXAMPLEB: "ExampleBWnd::createChildWindows"
  177. //
  178. int ExampleBWnd::createChildWindows( void )
  179. {
  180.   // So?  What shall we do today?
  181.  
  182.   // Well, we're inherited from a tabsheet.  That means we can make lots of
  183.   // little children windows that do their own thing, create them here, add
  184.   // them into ourselves, and then have them be properly initialized and
  185.   // functional automatically by the system.
  186.   //
  187.   // Slikschiznitz, eh?
  188.  
  189.   // SO OKAY, now that we know that we are a tabsheet, I guess we start 
  190.   // stuffing kiddie windows into everything.
  191.  
  192.   // First we'll use the custom-blitting window code we created in Example1.  That's
  193.   // a good way to start.  So, follow along here:
  194.  
  195.   // *** For a child of a tabsheet, the name of the window becomes the name
  196.   //     listed on the tab.  So, the instructions here are:
  197.   //
  198.   //    1) Instantiate your child window object.
  199.   Example1Wnd *myExample1Wnd = new Example1Wnd();
  200.   //    2) Give it a name (altho you might have your own custom window
  201.   //        give itself its own name).  For Tabsheet objects, the name
  202.   //        of the child object becomes the name in the tag.
  203.   myExample1Wnd->setName(_("Boring"));
  204.   //    3) Add it as a simple child to yourself.
  205.   //        NOTE: The "Add Child" method for TabSheet allows the specification
  206.   //        of a "TIP" string. 
  207.   addChild(myExample1Wnd,_("This is a boring version of ``hello world''"));
  208.   // WIP: AFAICT, the tip string is currently ignored.  But that won't crush
  209.   // us, and it won't stop us from hoping that, one day, all the tip strings
  210.   // in all the world can stand together hand in hand in the light of day without
  211.   // fear of hatred or reprisals or silly little api bugs that prevent them
  212.   // from attaining their full and complete and proper place in our society.
  213.  
  214.   //
  215.   // *** Note the _("...") object.  The _ object will feed your const string
  216.   //     through the localization and translation code to allow your strings
  217.   //     to be translated to other languages.
  218.  
  219.   //
  220.   // Here's another copy of the blitter window, in a second tab.
  221.   Example1Wnd *myExample1Wnd2 = new Example1Wnd( Example1Wnd::EXCITING );
  222.   myExample1Wnd2->setName(_("Exciting"));
  223.   addChild(myExample1Wnd2,_("This is a fun version of ``hello world''"));
  224.  
  225.   //
  226.   //  Now what we're going to do is have an individual method for the instantiation
  227.   //  and assembly of each tabsheet window.  First up will be the example sheet to
  228.   //  display the proper care and feeding of a gaggle of buttons whose button
  229.   //  functionality is tied to the core MP3 functionality:
  230.   createCoreButtonsSheet(); 
  231.  
  232.   //
  233.   //  This one will let you punch in an url to an XML sheet that will download and
  234.   //  display in a frame window assembly.
  235.   createFramesSheet();  
  236.  
  237.  
  238.   // Until we clear up the little retval issue around here (possibly in a later
  239.   // version of the SDK), return "0" for failure and "1" for success.
  240.   return 1;
  241. }
  242.  
  243. // ===========================================================================
  244. //
  245. //  EXAMPLEB: "ExampleBWnd::createCoreButtonsSheet"
  246. //
  247. int ExampleBWnd::createCoreButtonsSheet() { 
  248.   // Make some fun buttons that link to the core controls.
  249.  
  250.   // First thing we do is make a container to hold our buttons.
  251.   ContWnd * myButtonContainer = new ContWnd();
  252.   // Name him, for the tab.
  253.   myButtonContainer->setName(_("Buttons"));
  254.   // Add him to ourselves to make a new tab sheet.
  255.   addChild( myButtonContainer, _("This contains buttons that control core playback.") );
  256.  
  257.   //
  258.   //  *** Some things to know about ContWnd:
  259.   //
  260.   //      ContWnd is made to contain objects with fixed sizes in a fixed layout.
  261.   //      The addChild() method explicitly defines and sets the rectangular size
  262.   //      of the children being added.
  263.   //
  264.  
  265.   //
  266.   // Now we start making the children objects for the button container.
  267.   //
  268.  
  269.   // First thing we want to do is make up an inline counting system
  270.   // to allow us to more easily lay out our buttons.  The static inline
  271.   // method used here is defined at the top of the module.
  272.   int y = EXB_TOP_OFFSET; // used by PostIncReturn
  273.   // By creating this, I can be lazy and cut and paste my buttons without
  274.   // worrying about re-twiddling every pixel position by hand.
  275.  
  276.   // A play button would be nice.  So we make a button.
  277.   ButtonWnd *play = new ButtonWnd();
  278.   // Then we give it some text to display.
  279.   play->setButtonText("Play", 16);
  280.   // And assign a notification ID to it.
  281.   play->setButtonId(EXB_PLAY);
  282.   // And assign our object to handle all notifications from this button
  283.   play->setNotifyWindow(this);
  284.   // And finally add it to the container window.
  285.   myButtonContainer->addChild(play, EXB_LEFT_OFFSET, 
  286.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  287.     EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize*/);
  288.  
  289.   //
  290.   // NOTE:  The "Notify" stuff is where it all happens, but it's mildly complex.
  291.   //        checkout ExampleBWnd::childNotify() for where the magic happens.
  292.   //
  293.  
  294.   // How about a stop button?
  295.   ButtonWnd *stop = new ButtonWnd();
  296.   stop->setButtonText(_("Stop"), 16);
  297.   stop->setButtonId(EXB_STOP);
  298.   stop->setNotifyWindow(this);
  299.   myButtonContainer->addChild(stop, EXB_LEFT_OFFSET, 
  300.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  301.     EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  302.  
  303.  
  304.   // How about a pause button?
  305.   ButtonWnd *pause = new ButtonWnd();
  306.   pause->setButtonText(_("Pause"), 16);
  307.   pause->setButtonId(EXB_PAUSE);
  308.   pause->setNotifyWindow(this);
  309.   myButtonContainer->addChild(pause, EXB_LEFT_OFFSET, 
  310.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  311.     EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  312.  
  313.   // Space down by 2 yspacers.
  314.   PostIncReturn(y, EXB_BUTTON_SPACER + EXB_BUTTON_SPACER);
  315.  
  316.   // "Previous" button....
  317.   ButtonWnd *prev = new ButtonWnd();
  318.   prev->setButtonText(_("Previous"), 16);
  319.   prev->setButtonId(EXB_PREVIOUS);
  320.   prev->setNotifyWindow(this);
  321.   myButtonContainer->addChild(prev, EXB_LEFT_OFFSET, 
  322.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  323.     EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  324.  
  325.   // "Next" button....
  326.   ButtonWnd *next = new ButtonWnd();
  327.   next->setButtonText(_("Next"), 16);
  328.   next->setButtonId(EXB_NEXT);
  329.   next->setNotifyWindow(this);
  330.   myButtonContainer->addChild(next, EXB_LEFT_OFFSET, 
  331.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  332.     EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  333.  
  334.   // Space down by 4 yspacers.
  335.   PostIncReturn(y, EXB_BUTTON_SPACER * 4);
  336.  
  337.   // And create some text items.
  338.   TextBar *textbar = new TextBar();
  339.   textbar->setName(_("This is my text bar to say that the next text bars are my guid."));
  340.   myButtonContainer->addChild(textbar, EXB_LEFT_OFFSET, 
  341.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  342.     EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  343.  
  344.   // Want to display your GUID?
  345.   TextBar *guidbar = new TextBar();
  346.   char text[200];
  347.   // I'm being a dick and connecting to my guid as a global variable.
  348.   // that's lame and sloppy programming, kids.  never do that.  :)
  349.   extern GUID exb_guid;
  350.   guidbar->setName(nsGUID::toChar(exb_guid, text));
  351.   // Oh yah, and DON'T be a goddamn hypocrite, either!
  352.   // (inspect the "nsGUID::toChar" function, however)
  353.   myButtonContainer->addChild(guidbar, EXB_LEFT_OFFSET, 
  354.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  355.     EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  356.  
  357.   // Want to test that guids are being properly translated?
  358.   GUID testGUID = nsGUID::fromChar(text);
  359.  
  360.   // Want to display your crosstranslated GUID?
  361.   TextBar *testguidbar = new TextBar();
  362.   char testtext[200];
  363.   testguidbar->setName(nsGUID::toChar(testGUID, testtext));
  364.   myButtonContainer->addChild(testguidbar, EXB_LEFT_OFFSET, 
  365.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  366.     EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  367.  
  368.   // And one more text item for good measure, eh?
  369.   TextBar *textbar2 = new TextBar();
  370.   textbar2->setName(_("Are they equal?"));
  371.   myButtonContainer->addChild(textbar2, EXB_LEFT_OFFSET, 
  372.     PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
  373.     EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
  374.  
  375.  
  376.   // For the nonce, return codes from and to the API should
  377.   //  return "0" for failure and "1" for success.
  378.   return 1;
  379. }
  380.  
  381. // ===========================================================================
  382. //
  383. //  EXAMPLEB: "ExampleBWnd::childNotify"
  384. //
  385.  
  386. //
  387. //  Okay, so, we're going to use our single derived object to properly dispatch
  388. //  all the messaging from our children of myriad diversity.
  389. //
  390. //  This means I need to tell you about all the useful notification
  391. //  messages that you might encounter in your day to day life with
  392. //  our lovely little SDK:
  393. //
  394. //  *** BUTTON Notifications:
  395. //
  396. //    SO, firstly, we have buttons.  Stock ButtonWnd objects will send the
  397. //      following Notification messages:
  398. //
  399. //        CHILD_NOTIFY_LEFTPUSH          
  400. //        CHILD_NOTIFY_RIGHTPUSH         
  401. //        CHILD_NOTIFY_LEFTDOUBLECLICK   
  402. //        CHILD_NOTIFY_RIGHTDOUBLECLICK  
  403. //
  404. //    And the id that you assign to the button is sent as param1.
  405. //                                       
  406. int ExampleBWnd::childNotify (RootWnd *which, int msg, int param1, int param2) {
  407.  
  408. #   if 1  // WIP
  409.  
  410.   char text[200];
  411.   wsprintf(text,"Incoming rootWnd-childNotify: ptr:0x%08X msg:0x%03X p1:0x%08X p2:0x%08X \n",
  412.         which, msg, param1, param2);
  413.   OutputDebugString(text);
  414.  
  415. #   endif // WIP
  416.  
  417.   //
  418.   //  For the nonce, we're going to ignore the pointer to the object who is
  419.   //  sending the notification event.  Pointers are icky, smelly, and if you
  420.   //  touch them, you'll have to wash your hands with an aerosol oven cleaner
  421.   //  for a week just to make sure you're not accidentally besmirched.
  422.   //
  423.   //  OBVIOUSLY, if any of the objects you're using require an acknowledgement
  424.   //  or any other method to be called on them, you'll want to implement a
  425.   //  schema for your code that keeps the "which" pointer around.  But we're
  426.   //  not going to bother being that complicated here, kiddies.
  427.   //
  428.   //  Uncle mig's got a deadline, you know.
  429.   //
  430.   handleChildNotify(msg, param1, param2);
  431.  
  432.   return EXAMPLEBWND_PARENT::childNotify(which, msg, param1, param2);
  433. }
  434.  
  435.  
  436. // ===========================================================================
  437. //
  438. //  EXAMPLEB: "ExampleBWnd::handleChildNotify"
  439. //
  440. //    Just to show off message handling without pointers.
  441. //
  442. int ExampleBWnd::handleChildNotify (int msg, int param1, int param2) {
  443.   //
  444.   // We're all familiar with nested switch for event handling.
  445.   // There's nothing scary to be seen, here.
  446.   switch(msg)
  447.   {
  448.     // Messages from our buttons being pushed.
  449.     case CHILD_NOTIFY_LEFTPUSH          :
  450.     case CHILD_NOTIFY_RIGHTPUSH         :
  451.     case CHILD_NOTIFY_LEFTDOUBLECLICK   :
  452.     case CHILD_NOTIFY_RIGHTDOUBLECLICK  :
  453.     {
  454.       //
  455.       // So, now, what we're going to do here is if ANY of those
  456.       // messages came in, we just check which object ID shot that
  457.       // message out in order to know what to do with it.
  458.       //
  459.       int ButtonID = param1; // Just a clarification assignment.
  460.       // Switch on the ID to call the core handle.
  461.       switch(ButtonID)
  462.       {
  463.         case EXB_PREVIOUS:
  464.         {
  465.           OutputDebugString(_("Button pushed corresponds to EXB_PREVIOUS ButtonID\n"));
  466.           CoreHandle newHandle;
  467.           newHandle.prev();
  468.           break;
  469.         }
  470.  
  471.         case EXB_PLAY:
  472.         {
  473.           OutputDebugString(_("Button pushed corresponds to EXB_PLAY ButtonID\n"));
  474.           CoreHandle newHandle;
  475.           newHandle.play();
  476.           break;
  477.         }
  478.  
  479.         case EXB_PAUSE:
  480.         {
  481.           OutputDebugString(_("Button pushed corresponds to EXB_PAUSE ButtonID\n"));
  482.           CoreHandle newHandle;
  483.           newHandle.pause();
  484.           break;
  485.         }
  486.  
  487.         case EXB_STOP:
  488.         {
  489.           OutputDebugString(_("Button pushed corresponds to EXB_STOP ButtonID\n"));
  490.           CoreHandle newHandle;
  491.           newHandle.stop();
  492.           break;
  493.         }
  494.  
  495.         case EXB_NEXT:
  496.         {
  497.           OutputDebugString(_("Button pushed corresponds to EXB_NEXT ButtonID\n"));
  498.           CoreHandle newHandle;
  499.           newHandle.next();
  500.           break;
  501.         }
  502.  
  503.         // Ah!  THIS button is created and used on the "Frames" sheet, in the other module.
  504.         case EXB_XML_GO:
  505.         {
  506.           OutputDebugString(_("Button pushed corresponds to EXB_XML_GO ButtonID\n"));
  507.           // And you'll find this method there, as well.
  508.           startURLDownload();
  509.           break;
  510.         }
  511.  
  512.         default:
  513.           // Hrrmph.
  514.           return 0;
  515.       }
  516.     }
  517.     break;
  518.  
  519.     default:
  520.       // Hrrmph.
  521.       return 0;
  522.   }
  523.  
  524.   //
  525.   // Yawn.  Do I care about my error condition, here?
  526.   //
  527.   //  Oh PROBABLY.
  528.   //
  529.   //            SOMEWHERE.
  530.   //
  531.   //  Maybe in North Dakota or something.
  532.   //
  533.   //      So, if you're a developer, and you're IN North Dakota, well,
  534.   //      I feel so sorry for you that I'd suggest immediately changing
  535.   //      the return value here from a 1 to a 0.  It won't make a big
  536.   //      difference in the functionality here, but it will help bring
  537.   //      unto you that most invaluable of gifts:
  538.   //
  539.   //                  Peace of mind.
  540.   //
  541.   //  See, aren't I a great pal?
  542.   return 1;
  543. }
  544.